package cn.turboinfo.dongying.api.gateway.admin.framework.http;

import cn.turboinfo.dongying.api.entity.admin.constant.AdminRestConstants;
import cn.turboinfo.dongying.api.entity.admin.exception.user.SysUserNotLoginException;
import cn.turboinfo.dongying.api.gateway.admin.framework.http.fo.RestResponseFO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * author: sunshow.
 */
@Slf4j
@RestControllerAdvice(basePackages = {
        "cn.turboinfo.dongying.api.gateway.admin.controller",
})
public class AdminExceptionAdvice {

    private static ResponseEntity<RestResponseFO> doInExceptionHandler(Throwable e) {
        log.error(e.getMessage(), e);

        String message = e.getMessage();
        int code = AdminRestConstants.RC_ERROR_DEFAULT;

        if (e instanceof ResponseBodyWrapperException exception) {
            code = exception.getCode();
            message = exception.getMessage();

            return new ResponseEntity<>(RestResponseFO.error(code, message, exception.getData()), HttpStatus.INTERNAL_SERVER_ERROR);
        } else if (e instanceof UnauthorizedException) {
            message = "没有权限执行当前的操作";
            code = AdminRestConstants.RC_ERROR_UNAUTHORIZED;
            return new ResponseEntity<>(RestResponseFO.error(code, message), HttpStatus.FORBIDDEN);
        } else if (e instanceof SysUserNotLoginException) {
            message = "未登录";
            code = AdminRestConstants.RC_ERROR_UNAUTHENTICATED;
            return new ResponseEntity<>(RestResponseFO.error(code, message), HttpStatus.UNAUTHORIZED);
        } else if (e instanceof MethodArgumentNotValidException) {
            BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            List<String> errorList = new ArrayList<>();
            bindingResult.getAllErrors().forEach(err -> errorList.add(err.getDefaultMessage()));
            message = "参数验证出错: " + StringUtils.join(errorList, "; ");
            code = AdminRestConstants.RC_ERROR_BAD_REQUEST;
            return new ResponseEntity<>(RestResponseFO.error(code, message), HttpStatus.BAD_REQUEST);
        } else if (e instanceof ConstraintViolationException constraintViolationException) {
            message = constraintViolationException.getConstraintViolations()
                    .stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(","));
            code = AdminRestConstants.RC_ERROR_BAD_REQUEST;
            return new ResponseEntity<>(RestResponseFO.error(code, message), HttpStatus.BAD_REQUEST);
        }

        return new ResponseEntity<>(RestResponseFO.error(code, message), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(Throwable.class)
    public ResponseEntity<RestResponseFO> exceptionHandler(Throwable e) {
        return doInExceptionHandler(e);
    }

    @Slf4j
    @RestControllerAdvice(basePackages = {
            "cn.turboinfo.dongying.api.gateway.web.framework.http",
    })
    public static class AdminErrorHandler {

        @ExceptionHandler(AdminServletWrapperException.class)
        public ResponseEntity<RestResponseFO> adminServletWrapperExceptionHandler(AdminServletWrapperException e) {
            return doInExceptionHandler(e.getCause());
        }

    }

}
